{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python Image I/O\n",
    "\n",
    "`skia-python` supports several conversion between common data types in Python.\n",
    "\n",
    "- [Image files](#Reading-and-writing-to-image-files)\n",
    "- [NumPy array](#Numpy-array)\n",
    "- [PIL Image](#Converting-image-from/to-PIL)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import skia\n",
    "import PIL.Image\n",
    "import numpy as np\n",
    "import io\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from IPython.display import display"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reading and writing to image files"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`skia.Image` is the primary read-only image data structure in Skia. `skia.Image` can be read from an image file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "Image(100, 100, ColorType.kRGBA_8888_ColorType, AlphaType.kPremul_AlphaType)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "image = skia.Image.open('../skia/resources/images/rainbow-gradient.png')\n",
    "\n",
    "display(image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or, can be exported via `skia.Surface.makeImageSnapshot` call:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABHNCSVQICAgIfAhkiAAABHRJREFUeJztnF9olXUYxz9H23Zi52wXtT+a2JQhMXbRVUkKgV6kG4pIeJEXg26FLAyyXWR1c4SESrxOwi6kCxF1syKSQMO6CcaIGkNNbG6zLnZ20M3Fvl3EhgmjHTzn+T1nPh/4XZyLc77P8374vZz3fX/vLyMhAjesSl1A8F9CiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDNCiDOeSF1AuZxjN1fYwi3WMcbaxQE88GmMddxiK5fZxfnEFZdHxvvKxRI5BujlDHsZpIcSubK+n2eaHgbZyxl6GCRHqUqVVggJeRzTyuk9faCcpiv2q3kVdUTvq6h88v6WGu6EzKpeH+tNtWiyaiktmtSnekOzqk/er2shw+pSl4bNErs1pBF1Ju/bpZBT2q8G3TNPzqmok+pL3r8bIdNq1H6dSn4o+nRSd5V9vIUMq0sbNZpcxsLo1pCG1J20imR/e+fJsJOLfMMrKeKXZAcXGaCXVYmuBpJdqfdTcCcD4Ct20k8hXQEppuWXejX56en/xmntezxOWRO0sokRijRbxpZNE1PcZD3NFE1zzU9ZBfrdywAo0kyBfvNc0xkyQSvP8juzZK0iH4kGZrhBB+1MmGWazpAjfFgzMgBmyXKUd00zzWbIdTroZJR5VlvEVYwGZviFLjZy3STPbIZ8zY6akwH/zhLLv+dmQs6yxyqq4ljWbnLKKpLnaf5kjvpqR1WFOu5TIkc9c1XPMpkhg/TWrAyAOer5ju0mWSZCfuU5i5iqcpXNJjkmQm7QYRFTVax6CCHLZEUJGafdIqaqWPUQQpbJihISLB8TIe2MW8RUFaseQsgyCSHOCCHOWFFCNnPVIqaqWPVgcnNxiiZauFOz97PquM9fPEXeYOW8yQxppsg2LllEVYVtXDKRAYbXIXs4axVVcSxrN3uEO8YanuEPIGMRV0HEbdaYLXQwmyFruc1BjlvFVYyDHDdddWK+DKgWFsktkKfIKJ20cscs0/ReVhuTvMUnlpGPRD8FUxmQ4KXPKZrYxAiTtFnGlk0Lk9xkPVlmTXPN7/Y2U+QzXifDvHX0sskwz+f0mcsA0r2FW9Dh5CvclxoFHU6WnkyIhHp0IfnBf3js0+mkFSTdOGCKJl7kR35zsirleX7mB17iSWaS1ZD0iWEzRX7iBbbzbcoyAOjlAt/zclIZgI+dHP7War2jo8kqeFsfaV6Z5MdBcvBa9IPjC72mOs2aJWZ1N9mrazUhRELXtEEHdELZKm4ikNU9HdAJXdOG5P26F7IwxtWmQzqmRpUq9quNKumQjmlcbcn7W2rUxPZMg/Qsbs80Tb6s7+coLW7P1MuA++2Z3At5mPPs4jJbl7WB2RausJtziSsuj5oTstKJlYvOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHOCCHO+AdScgYxkP93WAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "Image(100, 100, ColorType.kRGBA_8888_ColorType, AlphaType.kPremul_AlphaType)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "surface = skia.Surface(100, 100)\n",
    "with surface as canvas:\n",
    "    canvas.clear(skia.ColorYELLOW)\n",
    "    paint = skia.Paint(AntiAlias=True, Color=skia.ColorCYAN)\n",
    "    canvas.drawCircle((50, 50), 25, paint)\n",
    "image = surface.makeImageSnapshot()\n",
    "\n",
    "display(image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following resizes the image:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAAg9JREFUaIHtmD9v00AYh39xUokCU2krt1IklCDUPwwFBOqH6EYXBgYkliAY4TvABiIDAwMDC6z9Cl2oFCHSdqChajtYKUoXoEhVsR4GlBHInc/OKdwj3eb3fn7sxPfelUBoBIiGfQOuCCK+EUR8I4j4RhDxjSDiG5W8Jn6vG/qsS0o0K0maVaK6OrqpjXwCQbgaO9Rp0CQm+eNVMyTc5wU71J3lgnAi8p2zPOA5Y5wMXDXGCQ95xjHjfoi0WWSBTesZFmizyfxwRdZZ5gw/Mj/Pc3xjneXhiBwyRZV9Bz+K36PKPodMFS9ymzfOJPrjDq+LFWmzSInUuUiJlC3L/4vVgvhUj0QOaymK9ESPrWpLYHb48FNlxerqSJNWgf/ignr6omlFhmcixo+1peu5SUjSkSb1QVeN64xFdlUzDjHlky4b1xiL9HunPLHJGJnu11gkVjeP+8icYSxyUXvGIUVkePn57SpWRalRnfEbqSjVitZMywZmRWvGEpLsNlZbzFPm1HmLUubUukWxEgFxl1fORe7x0rraWqTHBDU6ziRqdOgxUbwIiBZLjHOcWeI8X/nIlUyzZBIBscG1TBusKge0WMr8TjOLgOgyzS3eERnsUSJSVnmbaVfoXKQ/tpmjQZOZvxwHxSQ0aLLNnLNcEMYL4qAUfUCXm0jR/L/dr68EEd8IIr4RRHwjiPjGyIj8AuH5Z0Q/tKVbAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "Image(50, 50, ColorType.kRGBA_8888_ColorType, AlphaType.kPremul_AlphaType)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "display(image.resize(50, 50))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Write to a specific image format is available via `skia.Image.save` or `skia.Image.encodeToImage`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'RIFFd\\x03\\x00\\x00WEBPVP8L'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os\n",
    "import io\n",
    "import tempfile\n",
    "\n",
    "with tempfile.TemporaryDirectory() as t:\n",
    "    image.save(os.path.join(t, 'output.png'), skia.kPNG)\n",
    "    image.save(os.path.join(t, 'output.jpg'), skia.kJPEG, quality=95)\n",
    "    \n",
    "data = image.encodeToData(skia.kWEBP, 100)\n",
    "bytes(data)[:16]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NumPy array\n",
    "\n",
    "`skia.Image` supports NumPy array import and export via `fromarray` and `toarray` methods:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAGJJREFUeJzt0IENgCAQBEG0/56xCIUNcaYA2L8xAAAAAACAv7g2/DEXv//qhvurilMZoA6oGaAOqBmgDqgZoA6oGaAOqBmgDqgZoA6oGaAOqBmgDqgZoA6oGaAOAAAAANjtATuzATANtKc0AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "Image(64, 64, ColorType.kRGBA_8888_ColorType, AlphaType.kUnpremul_AlphaType)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "array = np.zeros((64, 64, 4), dtype=np.uint8)\n",
    "array[24:48, 24:48, 3] = 255\n",
    "\n",
    "image = skia.Image.fromarray(array)\n",
    "display(image)\n",
    "\n",
    "image = skia.Image.open('../skia/resources/images/rainbow-gradient.png')\n",
    "array = image.toarray()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Also, NumPy arrays can be directly used as a pixel buffer behind `skia.Canvas`. This approach enables direct drawing into the given array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 144x144 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "array = np.zeros((256, 256, 4), dtype=np.uint8)\n",
    "\n",
    "with skia.Surface(array) as canvas:\n",
    "    paint = skia.Paint(AntiAlias=True, Color=skia.ColorCYAN)\n",
    "    canvas.drawCircle((128, 128), 64, paint)\n",
    "\n",
    "plt.figure(figsize=(2, 2))\n",
    "plt.imshow(array)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One pitfall is that generic pixel format is usually unpremultiplied alpha (`skia.kUnpremul_AlphaType`), but skia defaults to premultiplied alpha (`skia.kPremul_AlphaType`). Don't forget to specify `alphaType` parameter when needed."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Many APIs in skia do not copy buffer data but only shares a reference. Therefore, buffer lifetime should be carefully taken into account when converting between different format. The following results in crash.\n",
    "\n",
    "```python\n",
    "array = np.zeros((64, 64, 4), dtype=np.uint8)\n",
    "surface = skia.Surface(array)\n",
    "del array\n",
    "\n",
    "surface.makeImageSnapshot()  # This will crash\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Canvas or surface can also export to numpy array. This is convenient when surface backend is not raster."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 288x576 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "surface = skia.Surface(128, 128)\n",
    "canvas = surface.getCanvas()\n",
    "paint = skia.Paint(AntiAlias=True, Color=skia.ColorCYAN)\n",
    "canvas.drawCircle((64, 64), 32, paint)\n",
    "\n",
    "plt.figure(figsize=(4, 8))\n",
    "plt.subplot(1, 2, 1), plt.imshow(canvas.toarray())\n",
    "plt.subplot(1, 2, 2), plt.imshow(surface.toarray())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Converting image from/to PIL\n",
    "\n",
    "It is possible to directly convert `skia.Image`, `skia.Bitmap` or `skia.Pixmap` to `PIL.Image` using `fromarray` method.\n",
    "\n",
    "Note that `PIL.Image` supports limited image modes. Apart from `skia.kRGBA_8888_ColorType` format, many pixel formats in skia are not compatible.\n",
    "\n",
    "Default alpha type of `skia.Image` is `skia.kPremul_AlphaType`. To convert `skia.Image` to `PIL.Image`, make sure to first convert the alpha type before calling `fromarray`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "skia_image = skia.Image.open('../skia/resources/images/rainbow-gradient.png')\n",
    "\n",
    "pil_image = PIL.Image.fromarray(skia_image.convert(alphaType=skia.kUnpremul_AlphaType))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, use `RGBa` (premultiplied alpha mode) in `PIL.Image`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "pil_image = PIL.Image.fromarray(skia_image, 'RGBa')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Image is also convertible via encoded image buffer:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "with io.BytesIO(skia_image.encodeToData()) as f:\n",
    "    pil_image = PIL.Image.open(f)\n",
    "    pil_image.load()  # Ensure to make a copy of buffer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Importing a `PIL.Image` requires conversion to supported color type:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "pil_image = PIL.Image.open('../skia/resources/images/rainbow-gradient.png')\n",
    "skia_image = skia.Image.frombytes(\n",
    "    pil_image.convert('RGBA').tobytes(), pil_image.size, skia.kRGBA_8888_ColorType)\n",
    "\n",
    "skia_image = skia.Image.frombytes(\n",
    "    pil_image.convert('RGBX').tobytes(), pil_image.size, skia.kRGB_888x_ColorType)\n",
    "\n",
    "skia_image = skia.Image.frombytes(\n",
    "    pil_image.convert('L').tobytes(), pil_image.size, skia.kGray_8_ColorType)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, it is possible to use encoded bytes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "pil_image = PIL.Image.open('../skia/resources/images/rainbow-gradient.png')\n",
    "\n",
    "with io.BytesIO() as f:\n",
    "    pil_image.save(f, 'png')\n",
    "    skia_image = skia.Image.open(f)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
